﻿Imports System.Activities
Imports System.Activities.Presentation.Metadata
Imports System.ComponentModel
Imports System.Drawing
Imports System.Net
Imports System.IO
Imports System.Security.Cryptography.X509Certificates
Imports System.Net.Security

Public MustInherit Class WebBase
    Inherits AsyncCodeActivity
    Implements IRegisterMetadata

#Region "プロパティ定義 Proeprty"
    Public Property Address As InArgument(Of String)
    Public Property ContentType As InArgument(Of String)
    Public Property RequestHeader As InArgument(Of String)
    Public Property RequestBody As InArgument(Of String)
    Public Property UseIllegalSSL As InArgument(Of Boolean) = False
    Public Property UserAgent As InArgument(Of String)

    Public Property StatusCode As OutArgument(Of Integer)
    Public Property ResponseHeader As OutArgument(Of String)
    Public Property ResponseBody As OutArgument(Of String)

    Public Property CookieContainer As InOutArgument(Of CookieContainer)
#End Region


    Protected _verbs As String = ""

    Protected Delegate Function delegateExecuteWebRequest(ByVal webValues As WebRequestVariablesInPrivate) As WebRequestVariablesInPrivate

    Protected Overrides Function BeginExecute(context As System.Activities.AsyncCodeActivityContext, callback As System.AsyncCallback, state As Object) As System.IAsyncResult
        Dim add = context.GetValue(Me.Address)
        Dim ctp = context.GetValue(Me.ContentType)
        Dim reqHead = context.GetValue(Me.RequestHeader)
        Dim reqBody = context.GetValue(Me.RequestBody)
        Dim useIllegal = context.GetValue(Me.UseIllegalSSL)
        Dim uaString = context.GetValue(Me.UserAgent)
        Dim cookie = context.GetValue(Me.CookieContainer)
        Dim wVal As New WebRequestVariablesInPrivate With {
            .Address = add, .Verb = _verbs}

        If ctp IsNot Nothing Then wVal.ContentType = ctp
        If uaString IsNot Nothing Then wVal.UserAgent = uaString
        If useIllegal Then wVal.UseIllegalSSL = useIllegal
        If reqHead IsNot Nothing AndAlso reqHead.Trim <> "" Then wVal.RequestHeades = reqHead
        If reqBody IsNot Nothing AndAlso reqBody.Trim <> "" Then wVal.RequestBodies = reqBody
        If cookie IsNot Nothing Then wVal.CookieContainer = cookie

        Dim asyncExecute = New delegateExecuteWebRequest(AddressOf ExecuteWebRequest)
        context.UserState = asyncExecute

        Return asyncExecute.BeginInvoke(wVal, callback, state)
    End Function

    Protected Overrides Sub EndExecute(context As System.Activities.AsyncCodeActivityContext, result As System.IAsyncResult)
        Dim asyncExecute = TryCast(context.UserState, delegateExecuteWebRequest)
        Dim execResult = asyncExecute.EndInvoke(result)

        context.SetValue(Me.StatusCode, execResult.Status)
        context.SetValue(Me.ResponseHeader, execResult.ResponsHeades)
        context.SetValue(Me.ResponseBody, execResult.ResponsBodies)
        context.SetValue(Me.CookieContainer, execResult.CookieContainer)
    End Sub

    Public Overridable Sub Register() Implements System.Activities.Presentation.Metadata.IRegisterMetadata.Register
        Dim build As New AttributeTableBuilder
        'WebBase Activity
        build.AddCustomAttributes(GetType(WebBase), "DisplayName",
                                      New CategoryAttribute(My.Resources.CategorySetting),
                                      New DisplayNameAttribute(My.Resources.DisplayNameDisplay))
        build.AddCustomAttributes(GetType(WebBase), "Address",
                                      New RequiredArgumentAttribute,
                                      New CategoryAttribute(My.Resources.CategoryDetail),
                                      New DisplayNameAttribute(My.Resources.AddressDisplay),
                                      New DescriptionAttribute(My.Resources.AddressDescription))
        build.AddCustomAttributes(GetType(WebBase), "ContentType",
                                      New CategoryAttribute(My.Resources.CategoryDetail),
                                      New DisplayNameAttribute(My.Resources.ContentTypeDisplay),
                                      New DescriptionAttribute(My.Resources.ContentTypeDescription))
        build.AddCustomAttributes(GetType(WebBase), "RequestHeader",
                                      New CategoryAttribute(My.Resources.CategoryDetail),
                                      New DisplayNameAttribute(My.Resources.RequestHeaderDisplay),
                                      New DescriptionAttribute(My.Resources.RequestHeaderDescription))
        build.AddCustomAttributes(GetType(WebBase), "RequestBody",
                                      New CategoryAttribute(My.Resources.CategoryDetail),
                                      New DisplayNameAttribute(My.Resources.RequestBodyDisplay),
                                      New DescriptionAttribute(My.Resources.RequestBodyDescription))
        build.AddCustomAttributes(GetType(WebBase), "UseIllegalSSL",
                                      New RequiredArgumentAttribute,
                                      New CategoryAttribute(My.Resources.CategoryDetail),
                                      New DisplayNameAttribute(My.Resources.UseIllegalSSLDisplay),
                                      New DescriptionAttribute(My.Resources.UseIllegalSSLDescription))
        build.AddCustomAttributes(GetType(WebBase), "UserAgent",
                                      New CategoryAttribute(My.Resources.CategoryDetail),
                                      New DisplayNameAttribute(My.Resources.UserAgentDisplay),
                                      New DescriptionAttribute(My.Resources.UserAgentDescription))

        build.AddCustomAttributes(GetType(WebBase), "StatusCode",
                                      New CategoryAttribute(My.Resources.CategoryDetail),
                                      New DisplayNameAttribute(My.Resources.StatusCodeDisplay),
                                      New DescriptionAttribute(My.Resources.StatusCodeDescription))
        build.AddCustomAttributes(GetType(WebBase), "ResponseHeader",
                                      New CategoryAttribute(My.Resources.CategoryDetail),
                                      New DisplayNameAttribute(My.Resources.ResponseHeaderDisplay),
                                      New DescriptionAttribute(My.Resources.ResponseHeaderDescription))
        build.AddCustomAttributes(GetType(WebBase), "ResponseBody",
                                      New CategoryAttribute(My.Resources.CategoryDetail),
                                      New DisplayNameAttribute(My.Resources.ResponseBodyDisplay),
                                      New DescriptionAttribute(My.Resources.ResponseBodyDescription))

        build.AddCustomAttributes(GetType(WebBase), "CookieContainer",
                                      New CategoryAttribute(My.Resources.CategoryDetail),
                                      New DisplayNameAttribute(My.Resources.CookieContainerDisplay),
                                      New DescriptionAttribute(My.Resources.CookieContainerDescription))


        MetadataStore.AddAttributeTable(build.CreateTable)
    End Sub

    Protected Overridable Function ExecuteWebRequest(ByVal webValues As WebRequestVariablesInPrivate) As WebRequestVariablesInPrivate
        Dim result As WebRequestVariablesInPrivate = Nothing

        Dim postData As Byte() = Nothing
        Dim wrq = HttpWebRequest.Create(webValues.Address)
        If (webValues.CookieContainer IsNot Nothing) AndAlso
            (TypeOf wrq Is HttpWebRequest) Then
            DirectCast(wrq, HttpWebRequest).CookieContainer = webValues.CookieContainer
        End If
        If (webValues.UserAgent.Trim <> "") AndAlso
            (TypeOf wrq Is HttpWebRequest) Then
            DirectCast(wrq, HttpWebRequest).UserAgent = webValues.UserAgent
        End If
        If webValues.UseIllegalSSL Then
            ServicePointManager.ServerCertificateValidationCallback = New RemoteCertificateValidationCallback(AddressOf OnRemoteCertificateValidationCallback)
        End If
        If webValues.ContentType.Trim <> "" Then
            wrq.ContentType = webValues.ContentType
        End If

        wrq.Method = webValues.Verb
        If webValues.RequestHeades.Length > 0 Then
            For Each hd In webValues.RequestHeades.Split(ControlChars.NewLine)
                wrq.Headers.Add(hd)
            Next
        End If

        If webValues.RequestBodies.Length > 0 Then
            postData = System.Text.Encoding.ASCII.GetBytes(webValues.RequestBodies)
            wrq.ContentLength = postData.Length
        End If

        'リクエストの送信
        If (postData IsNot Nothing) AndAlso (postData.Length > 0) Then
            Try
                Using reqStr = wrq.GetRequestStream
                    If postData.Length > 0 Then reqStr.Write(postData, 0, postData.Length)
                End Using
            Catch ex As Exception
                Console.WriteLine(ex.Message)
                Return result
            Finally
                If (TypeOf wrq Is HttpWebRequest) Then
                    webValues.CookieContainer = DirectCast(wrq, HttpWebRequest).CookieContainer
                End If
            End Try
        End If

        'レスポンスの受信
        Dim wrs = wrq.GetResponse
        Dim hwrs = TryCast(wrs, HttpWebResponse)
        Dim enc = System.Text.Encoding.UTF8

        Try
            Using resStr = wrs.GetResponseStream

                If (hwrs IsNot Nothing) AndAlso (hwrs.ContentEncoding <> "") Then
                    enc = System.Text.Encoding.GetEncoding(hwrs.ContentEncoding)
                End If
                Dim resHead As New System.Text.StringBuilder
                For Each hs In hwrs.Headers.AllKeys
                    Dim vl = hwrs.Headers.GetValues(hs)
                    If vl IsNot Nothing Then
                        resHead.Append(hs + ":")
                        Dim firstValue = True
                        For Each value In vl
                            If Not firstValue Then
                                resHead.Append(",")
                            Else
                                firstValue = False
                            End If
                            resHead.Append(value)
                        Next
                        resHead.Append(ControlChars.NewLine)
                    End If
                Next
                webValues.ResponsHeades = resHead.ToString

                Using res As New StreamReader(resStr, enc)
                    webValues.ResponsBodies = res.ReadToEnd
                End Using
            End Using
        Catch ex As Exception

        Finally
            webValues.Status = Convert.ToInt32(DirectCast(wrs, System.Net.HttpWebResponse).StatusCode)
            webValues.StatusDescription = DirectCast(wrs, System.Net.HttpWebResponse).StatusDescription
            result = webValues
        End Try

        Return result
    End Function

    ''' <summary>強制的に SSL 証明書を許可する</summary>
    ''' <remarks>SSL certificate to allow, Forcibly</remarks>
    Private Function OnRemoteCertificateValidationCallback(ByVal sender As Object, ByVal certificate As X509Certificate, _
                                                                                  ByVal chain As X509Chain, ByVal sslPolicyErrors As SslPolicyErrors) As Boolean
        Return True
    End Function

    Public NotInheritable Class WebRequestVariablesInPrivate

        Public Property Address As String = ""
        Public Property UseIllegalSSL As Boolean = False

        Public Property Verb As String = ""
        Public Property ContentType As String = ""
        Public Property UserAgent As String = ""
        Public Property RequestHeades As String = ""
        Public Property RequestBodies As String = ""
        Public Property ResponsHeades As String = ""
        Public Property ResponsBodies As String = ""

        Public Property Status As Integer = 0
        Public Property StatusDescription As String = ""

        Public Property CookieContainer As CookieContainer = Nothing
    End Class

End Class
